﻿/**
 * jQuery twiDataTable plugin
 * @author: feitianxinhong  http://xuzhihong1987.blog.163.com/
 * @version 1.1.1
 * @create date:2014-10-25
 * @copyright (c) 2014 feitianxinhong/tyingsoft/twilight  http://www.tyingsoft.com
 * @example Visit 
 * @Require: bootstrap-3.2.0样式 和 twibootstrap-1.1.1.css 样式
 *
 * ------------------------------------------------------------------
 * 编号    版本号     作者              修改日期        修改内容
 * ------------------------------------------------------------------
 *  1      1.0.0     feitianxinhong    2014-10-17     创建文件
 *  2      1.1.0     feitianxinhong    2014-10-24     增加了选择框来支持多选、增加了部分方法
 *  3      1.1.1     feitianxinhong    2014-10-25     增加了高度配置，滚动效果
 *
 * ------------------------------------------------------------------
 */

(function ($) {
    var global = this;
    if (typeof Twi === 'undefined') {
        global.Twi = {
            emptyFn: function () { }
        };
    }
    Twi.global = global;

    /**
     * config配置说明：
     *
     * idField:      '主键或唯一字段',
     * columns:[{
     *    text:      '表头标题【必填】',
     *    fieldName: '对应字段【必填】',
     *    dataType:  '数据类型，不填为字符串',
     *    width:     '列宽，不填则为自动',
     *    renderer:  '显示格式转换函数'
     *  }],
     * width:        'grid宽度，数字',
     * height:       'grid高度，数字',
     * renderTo:     '表格呈现的位置，默认为body，如果为id，则格式为：#id',
     * rownumberer:  '配置是否显示行号列，默认显示，如果为false时，不显示，可配置宽度width,默认为20px',
     * striped:      '是否隔行变色，default：true' , 
     * multiSelect:  '是否支持多选，default：false 【多选时，会自动显示checkbox列】',
     * checkBoxCol:  '配置是否显示选择框列,default：false，可配置宽度，默认为20px.'
     *
     * 事件配置说明： 
     *         1、事件名做为config配置时，需加前缀on，如事件rowclick，配置时为onrowclick
     *         2、事件名全部为小写 【Sencha Extjs 事件特殊命名规则】
     *
     * ---------------------------------------------------------------
     *
     * config中会在内容自动处理的属性（即使配置也会被重写）【私有属性，勿赋值】：
     *
     * config._needRowNumber:  '是否显示行号',
     * config._showCheckBox:   '是否显示选择框列'
     *
     * ----------------------------------------------------------------
     *
     * 属性说明:  
     * 
     *
     * 私有变量为下划线为前缀：
     *
     * _headHtml:'',             //Table表头HTML
     * _data：[],                //数组，本地的数据存储
     * _handlers:[],             //事件集合
     * _idFieldValues:[]         //idField对应值集合
     * ----------------------------------------------------------------
     * 
     * 事件说明：
     * rowclick(args)
     *     参数说明： 
     *              1、tableSelf : Twi.DataTable对象
     *              2、rowData:    行数据对象
     *              3、rowIndex：  行索引
     */
    Twi.DataTable = function (config) {
        var me = this;
        /**
         *默认配置项 
         */
        me.defaults = {
            renderTo: 'body',
            rownumberer: {
                text:'',
                width: 20
            },
            columns: [],
            striped: true,
            multiSelect: false,
            _showCheckBox:false
        };
        /**
         * 事件
         */
        me._handlers = {};

        config = config || {};
        config = $.extend({}, me.defaults, config);

        //是否需要显示行号
        config._needRowNumber = true;
        if (typeof config.rownumberer == 'boolean') {
            if (!config.rownumberer) {
                config._needRowNumber = false;
            }
            else {
                config.rownumberer = me.defaults.rownumberer; 
            }
        }

        /*选择框列*/
        config._showCheckBox = false;
        if (typeof config.checkBoxCol == 'boolean') {
            //多选时，会强制显示checkbox列
            if(config.checkBoxCol || config.multiSelect){ 
                config._showCheckBox = true;
                config.checkBoxCol = {
                    width:20
                };
            }
        }
        else if (typeof config.checkBoxCol == 'object') {
            config._showCheckBox = true;
            config.checkBoxCol.width = config.checkBoxCol.width || 20;  //列宽默认20px
        }
        else if (typeof config.checkBoxCol == 'undefined') {
            //多选时，会强制显示checkbox列
            if (config.multiSelect) {
                config._showCheckBox = true;
                config.checkBoxCol = {
                    width: 20
                };
            }
        }

        /*属性赋值*/
        me.config = config;
        me.frameId = "TwiDtPanel" + Math.floor(10000 * Math.random());
        me.id = "TwiDataTable" + Math.floor(10000 * Math.random()); //随机ID         
        me.titleId = "TwiDtTitle" + Math.floor(10000 * Math.random());        
        me._idFieldValues = [];
        me._data = [];

        /**
         *生成title标题HTML
         */
        function getTitleHtml() {
            var titleHtml = '';
            if (config.title) {
                titleHtml = '<div id="' + me.titleId + '" class="panel-heading">' + config.title + '</div>';               
            }
            return titleHtml;
        }

        /*主框体*/
        var mainFrameHtml = '';
        mainFrameHtml += '<div id="' + me.frameId + '" class="panel panel-default">';
        mainFrameHtml += getTitleHtml();
        //mainFrameHtml +='<div class="panel-body">';
        //mainFrameHtml +='</div>';
        mainFrameHtml += '<div twiFor="tableContainer" class="twiTableContainer"></div>';
        mainFrameHtml +='</div>';
        $(config.renderTo).append(mainFrameHtml);

        //宽度设置
        if (typeof me.config.width == 'number') {
            $('#' + me.frameId).css('width', me.config.width);
        }  

        /**
         * 生成head表头HTML
         */
        function getTableHeadHtml() {
            var headHtml = "";
            headHtml += '<thead>';
            headHtml += '<tr>';

            //行号列
            if (config._needRowNumber) {
                headHtml += '<th style="text-align:center;width:' + config.rownumberer.width + 'px;">' + config.rownumberer.text + '</th>';
            }

            //选择框列
            if (config._showCheckBox) {                
                headHtml += '<th style="text-align:center;width:' + config.checkBoxCol.width + 'px;">';
                headHtml += config.multiSelect ? '<input type="checkbox" twiDtChkType="all"/>' : "#";
                headHtml += '</th>';
            }

            //数据列
            for (var i = 0; i < config.columns.length; i++) {
                var col = config.columns[i];
                if (typeof col.width == 'number') {
                    headHtml += '<th style="width:' + col.width + 'px;">' + col.text + '</th>';
                }
                else {
                    headHtml += '<th>' + col.text + '</th>';
                }
            }

            headHtml += '</tr>';
            headHtml += '</thead>';
            return headHtml;
        }
        me._headHtml = getTableHeadHtml();

        /*表格*/
        var html = '';
        html += '<table id=' + me.id + ' class="table table-hover table-bordered';
        if (typeof me.config.striped == 'boolean' && me.config.striped) {
            //隔行变色
            html += ' table-striped';
        }
        html += '">';        
        html += me._headHtml;
        html += '<tbody></tbody>';
        html += '</table>';
        $('#' + me.frameId).children('div[twiFor="tableContainer"]').append(html);

        //高度设置
        if (typeof me.config.height == 'number') {
            $('#' + me.frameId).children('div[twiFor="tableContainer"]').css('height', me.config.height);
        }
        
        //注册全选和反选事件
        if (this.config._showCheckBox) {
            $('#' + me.id).children('thead').find(':checkbox[twiDtChkType="all"]').off('click').click(function () {
                if ($(this).prop('checked')) {
                    me.selectAll();
                }
                else {
                    me.unSelectAll();
                }
            });
        }
    }

    /**
     * 获取Id
     */
    Twi.DataTable.prototype.getId = function () {
        return this.id;
    }

    /**
     * 加载数据
     * @data: 【必填参数】，record对象数组，一般传twi.data
     */
    Twi.DataTable.prototype.loadData = function (data) {
        if (!(data  instanceof Array)) {
            return;
        }

        var tableSelf = this;
        var me = this;
        me._data = data;
        me._idFieldValues = [];

        //先清空数据
        $('#' + me.id).children('tbody').empty();

        /*添加数据行HTML*/
        for (var i = 0; i < data.length; i++) {
            var html = '<tr rowIndex="' + i + '">';
            //序号列
            if (me.config._needRowNumber) {
                html += '<td style="text-align:center;">' + (i + 1) + '</td>';
            }
            //数据行选择框列
            if (me.config._showCheckBox) {
                html += '<td><input type="checkbox" twiDtChkType="row"/></td>';
            }
            //数据列
            for (var j = 0; j < me.config.columns.length; j++) {
                html += '<td>' + data[i][me.config.columns[j].fieldName] + '</td>';                
            }
            html += '</tr>';
            $('#' + me.id).children('tbody').append(html);
            
            if (typeof me.config.idField == 'string') {
                me._idFieldValues.push(data[i][me.config.idField]);
            }
        }               

        /*行操作、选择行事件*/      
        $('#' + me.id).children('tbody').children('tr').each(function () {
            //jquery data 数据存储
            if (!$(this).data('rowIndex')) {
                $(this).data('rowIndex', $(this).attr('rowIndex'));
                $(this).data('rowData', me._data[$(this).data('rowIndex')]);
            }
        }).off('click').on('click', function () {
            //当前选择行样式
            $('#' + me.id).children('tbody').children('tr').removeClass('twiSelected');
            $(this).addClass('twiSelected');

            //如果是单选模式
            if (!me.config.multiSelect) {
                //单选时，选择行会自动勾选
                me.unSelectAll();
                $(this).find(':checkbox[twiDtChkType="row"]').prop('checked', true);      
            }         

            //自定义事件 rowclick
            me.fireEvent("rowclick", {
                tableSelf: tableSelf,               
                rowData: $(this).data('rowData'),
                rowIndex: $(this).data('rowIndex')
            });
        });

        /*如果有选择框列，注册checkbox选择和反选事件*/
        if (this.config._showCheckBox) {
            $('#' + me.id).children('tbody').find(':checkbox[twiDtChkType="row"]').off('click').click(function (event) {
                //checkbox 操作阻止事件冒泡
                event.stopPropagation();                

                if ($(this).prop('checked')) {
                    //当前选择行样式
                    $('#' + me.id).children('tbody').children('tr').removeClass('twiSelected');
                    $(this).parent().parent('tr').addClass('twiSelected');

                    if (me.config.multiSelect) {
                        var isAllSeleted = true; //是否数据行都选中了
                        $('#' + me.id).children('tbody').find(':checkbox[twiDtChkType="row"]').each(function () {
                            if (!$(this).prop('checked')) {
                                isAllSeleted = false;
                                return false;
                            }
                        });
                        $('#' + me.id).children('thead').find(':checkbox[twiDtChkType="all"]').prop('checked', isAllSeleted);
                    }
                    else {
                        //单选时，表头的checkbox不显示，只需要取消其他checkbox选择状态
                        me.unSelectAll();
                        $(this).prop('checked', true);
                    }
                }
                else {
                    //取消选择时把选择行样式去掉
                    $(this).parent().parent('tr').removeClass('twiSelected');
                    if (me.config.multiSelect) {
                        //取消全选
                        $('#' + me.id).children('thead').find(':checkbox[twiDtChkType="all"]').prop('checked', false);
                    }
                }
            });
        }
    }

    /**
     * 获取最后选择行信息【仅限单选模式有效,多选请使用getSelections()】
     * 
     */
    Twi.DataTable.prototype.getLastSelected = function () {
        var selections = this.getSelections();
        if (selections.length > 0) {
            return selections[0]
        }
        return undefined;
    }

    /**
     * 获取选择的集合
     */
    Twi.DataTable.prototype.getSelections = function () {
        var selections = [];
        //有选择框列的情况
        if (this.config._showCheckBox) {            
            $('#' + this.id).children('tbody').find(':checkbox[twiDtChkType]').each(function(){
                if ($(this).prop('checked')) {
                    selections.push($(this).parent().parent('tr').data('rowData'));
                }
            });                
        }
        else {
            //单项没有checkbox列，则通过样式选择
            $('#'+this.id).children('tbody').children('.twiSelected').each(function (index) {
                selections.push($(this).data('rowData'));
            });
        }        
        return selections;
    }

    /**
     * 选择所有行
     */
    Twi.DataTable.prototype.selectAll = function () {
        if (this.config._showCheckBox) {
            $('#' + this.id).find(':checkbox[twiDtChkType]').prop('checked', true);
        }
    }

    /**
     * 取消选择所有行
     */
    Twi.DataTable.prototype.unSelectAll = function () {
        if (this.config._showCheckBox) {
            $('#' + this.id).find(':checkbox[twiDtChkType]').prop('checked',false);
        }
    }

    /**
     * 根据键值对选中行【可能会选中多行】
     */
    Twi.DataTable.prototype.checkedByKeyValue = function (key, value) {
        var me = this;
        for (var i = 0; i < me._data.length; i++) {
            if (me._data[i][key] == value) {
                me.checkedByIndex(i);
            }
        }
    }

    /**
     * 根据idField的值选中行【如果idField未配置无效,由于默认idField唯一，所以只会选择第一个】
     *
     * @idFieldValue: idField对应行数据的值,
     *                     例如：rowData = {FCode:'001',FName:'xzh'},如果idField配置为FCode，则传001；
     *                     如果idField配置为FName，则传xzh。
     */
    Twi.DataTable.prototype.checkedById = function (idFieldValue) {
        var me = this;
        if (!me.config._showCheckBox || typeof me.config.idField != 'string') return;
        for (var i = 0; i < me._idFieldValues.length; i++) {
            if (me._idFieldValues[i] == idFieldValue) {
                me.checkedByIndex(i);
                break; //只会处理第一个
            }
        }
    }

    /**
     * 根据索引选中行
     */
    Twi.DataTable.prototype.checkedByIndex = function (index) {
        var me = this;
        if (!me.config.multiSelect) {
            me.unSelectAll(); //单选需取消之前的选择
        }
        if (me.config._showCheckBox) {
            $('#' + me.id).children('tbody').find(':checkbox[twiDtChkType]').eq(index).prop('checked',true);
        }
        else {
            //单选且无checkbox
            $('#' + me.id).children('tbody').children('tr').removeClass('twiSelected');
            $('#' + me.id).children('tbody').find('tr').eq(index).addClass('twiSelected');
        }
    }

    /**
     * 添加事件
     */
    Twi.DataTable.prototype.addListener = function (eventName, fn) {
        if (typeof this._handlers[eventName] == 'undefined') {
            this._handlers[eventName] = [];
        }
        if (typeof fn == "function") {
            this._handlers[eventName].push(fn);
        }
    }
    Twi.DataTable.prototype.on = Twi.DataTable.prototype.addListener;

    /**
     * 移除事件
     */
    Twi.DataTable.prototype.removeListener = function (eventName) {
        if (this._handlers[eventName] instanceof Array) {
            this._handlers[eventName] = undefined;
        }
    }
    Twi.DataTable.prototype.un = Twi.DataTable.prototype.off = Twi.DataTable.prototype.removeListener;

    /**
     * 触发事件
     * @eventName: 事件名称
     * @args: 参数对象
     */
    Twi.DataTable.prototype.fireEvent = function (eventName, args) {
        args = args || {};
        if (this._handlers[eventName] instanceof Array) {
            var fns = this._handlers[eventName];
            for (var i = 0; i < fns.length; i++) {
                fns[i](args);
            }
        }
    }

})(window.jQuery);

